// Tierless
// Copyright © 2010 Alphora
// This file is licensed under a modified BSD-license (see tierless_license.txt).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace Tierless.Framework.EntityTypes
{
	/// <summary>
	/// Provides a base class for the representation of entity definition objects within the entity model.
	/// </summary>
	[DataContract]
	public abstract class NamedEntityTypeObject
	{
		/// <summary>
		/// Initializes a new instance of the NamedEntityTypeObject class.
		/// </summary>
		/// <param name="name">The name of the object.</param>
		public NamedEntityTypeObject(string name)
		{
			if (String.IsNullOrEmpty(name))
				throw new ArgumentNullException("AName", "A name is required to create a named entity type object.");
			_name = name;
		}

		[DataMember]
		private string _name;

		/// <summary>
		/// Gets the name of the entity object.
		/// </summary>
		public string Name
		{
			get { return _name; }
		}

		private static object _knownTypesSync = new object();
		private static List<Type> _knownTypes;

		/// <summary>
		/// Gets a list of known types to be registered based on the set of types in the current assembly that descend from this class.
		/// </summary>
		/// <returns>The list of known types to be registered.</returns>
		public static List<Type> GetKnownTypes()
		{
			// TODO: allow other assemblies to register for this

			lock (_knownTypesSync)
			{
				if (_knownTypes == null)
				{
					_knownTypes = new List<Type>();
					foreach (var type in typeof (NamedEntityTypeObject).Assembly.GetTypes().Where(AType => AType.IsSubclassOf(typeof (NamedEntityTypeObject))))
					{
						_knownTypes.Add(type);
					}
				}
			}

			return _knownTypes;
		}

		/// <summary>
		/// Returns a string representation of the entity object.
		/// </summary>
		/// <returns>A string representation of the entity object.</returns>
		public override string ToString()
		{
			return String.Format("{0} : {1}", Name, GetType().Name);
		}

		/// <summary>
		/// Provides name-based equality semantics for entity objects.
		/// </summary>
		/// <param name="obj">The entity object to be tested.</param>
		/// <returns>True if the object is of the same type, and has the same name as this object, false otherwise.</returns>
		public override bool Equals(object obj)
		{
			return ((obj != null) && (obj.GetType().IsSubclassOf(GetType())) && (Name == ((NamedEntityTypeObject) obj).Name));
		}

		/// <summary>
		/// Provides name-based hashing semantics for entity objects.
		/// </summary>
		/// <returns>The hash code of the name of the object.</returns>
		public override int GetHashCode()
		{
			return Name.GetHashCode();
		}
	}
}